#!/usr/bin/python
# -*- coding: utf8 -*-

import sys
from sets import Set
from cargador_gramaticas import GramaticaELL1, vacio
from parser_ell1 import ParserELL1, GeneratingParserError


################################################
# Helpers para coloreo                         #
################################################

from color import TerminalController

def rojo(s):
    return TerminalController().render('${RED}%s${NORMAL}' % s)

def amarillo(s):
    return TerminalController().render('${YELLOW}%s${NORMAL}' % s)

def verde(s):
    return TerminalController().render('${GREEN}%s${NORMAL}' % s)

def mostrar_warning(s):
    '''Muestra un mensaje de advertencia formateado'''
    print
    print amarillo("--- Advertencia ---")
    print amarillo(s)
    print amarillo("-------------------")
    print

def mostrar_error(s):
    '''Muestra un mensaje de error formateado y sale del programa'''
    print
    print rojo("------ Error ------")
    print rojo(s)
    print rojo("-------------------")
    print
    sys.exit(1)



#################################################
# Lidio con las opciones de línea de comandos   #
#################################################

from optparse import OptionParser
usage = "%prog [opciones] entrada"
parser = OptionParser(usage=usage)
parser.add_option("-o", "--output", dest="outputfile", default=None,
                   help="escribir parser a ARCHIVO", metavar="ARCHIVO")
parser.add_option("-c", "--check", dest="check", default=False,
                   action="store_true",
                   help="unicamente valida la gramatica de entrada")
parser.add_option("-v", "--verbose", dest="verbose", default=False,
                   action="store_true",
                   help="mostrar informacion adicional")



#################################################
# Chequeos de gramática y parser                #
#################################################

def verificarInutiles(parser):
    inutiles = parser.getInutiles()
    if not vacio(inutiles):
        e = ['Los siguientes no terminales son inútiles:',
             '%s' % list(inutiles),
            ]
        mostrar_error('\n'.join(e))
            
def verificarAlcanzables(g):
    c = g.noTerminales
    if g.alcanzables() != c:
        w = ['Los siguientes no terminales son inalcanzables:',
             '%s' % list(c.difference(g.alcanzables())),
            ]
        mostrar_warning('\n'.join(w))
        


#################################################
# Main                                          #
#################################################

if __name__ == '__main__':
    (options, args) = parser.parse_args()

    # Verifico que se haya recibido un nombre
    # de archivo de entrada
    try:
        fname = args[0]
        assert(fname.strip())
    except:       
        mostrar_error("Debe especificar un archivo de entrada!\n\n" + \
                      "Ejecute pyllgen.py -h para ver la ayuda.")

    # Verifico que se pueda acceder al archivo de entrada
    try:
        f = file(fname, 'r')
    except:
        mostrar_error("No se pudo abrir el archivo '%s'!" % fname)

    # Intento parsear la gramática de entrada, y en caso de no
    # conseguirlo muestro un error por pantalla
    try:
        g = GramaticaELL1(f)
    except Exception, e:
        mostrar_error(e)
    
    verificarAlcanzables(g)

    # Intento generar el parser LL(1), y en caso de no
    # conseguirlo muestro un error por pantalla
    try:
        p =  ParserELL1(g)
    except GeneratingParserError, e:
        mostrar_error(e)
    
    verificarInutiles(p)

    # Comportamiento general del programa en
    # funcion de las opciones recibidas
    if options.verbose:
        print
        print g
        print
        print p

    if options.check: 
        if not options.verbose:
           print g
           print
        print verde("La gramática en %s es válida." % fname)
        sys.exit(0)

    else:
        if options.outputfile:
            try:
                f = open(options.outputfile, 'w')
                f.write(p.generarCodigo())
                f.close()
                print verde("El código se guardó con éxito en %s." % options.outputfile)
                print
                print verde("Para utilizar el parser ejecute:")
                print verde("python %s <cadena a parsear>" % options.outputfile)
            except:
                mostrar_error("No se pudo abrir el archivo %s para escritura" \
                    % options.outputfile)
        else:
            print p.generarCodigo()
